package com.example.fengyungo_user;

import android.util.Log;

import androidx.annotation.NonNull;

import java.io.IOException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;

/**
 * WebSocketClient
 *
 * @author XLR
 */
public class MyWebSocketClient extends WebSocketListener {

    private static final String TAG = "MyWebSocketClient";
    /**
     * 最大重连次数
     */
    private static final int MAX_RECONNECT_ATTEMPTS = 10;
    /**
     * 重连之间的延迟
     */
    private static final int RECONNECT_DELAY_MILLIS = 1000;
    /**
     * OkHttpClient
     */
    private OkHttpClient client;
    /**
     * url
     */
    private String url;
    /**
     * 用户id
     */
    private String userId;
    /**
     * WebSocket
     */
    WebSocket webSocket;
    /**
     * 重连次数
     */
    int reconnectCount;
    private ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
    public long lastPingTime = System.currentTimeMillis();

    /**
     * 构造方法
     *
     * @param url    String
     * @param userId String
     */
    public MyWebSocketClient(String url, String userId) {
        client = new OkHttpClient.Builder()
                // 设置读取超时时间
                .readTimeout(3000, TimeUnit.MILLISECONDS)
                .build();
        this.url = url;
        this.userId = userId;
    }

    @Override
    public void onOpen(@NonNull WebSocket webSocket, @NonNull Response response) {
        Log.d(TAG, "onOpen: Connected to server");
        // 启动心跳检测任务
        long heartbeatInterval = 5000;
        executor.scheduleAtFixedRate(() -> {
            if (System.currentTimeMillis() - lastPingTime > heartbeatInterval) {
                webSocket.send("ping"); // 发送心跳消息
                lastPingTime = System.currentTimeMillis();
            }
        }, heartbeatInterval, heartbeatInterval, TimeUnit.MILLISECONDS);
    }

    @Override
    public void onFailure(@NonNull WebSocket webSocket, Throwable t, Response response) {
        Log.d(TAG, "onFailure:");
        Log.d(TAG, "webSocket:" + webSocket);
        Log.d(TAG, "t.getMessage():" + t.getMessage());
        Log.d(TAG, "response:" + response);

        if (reconnectCount >= MAX_RECONNECT_ATTEMPTS) {
            Log.d(TAG, "Max reconnect attempts reached. Stopping reconnection.");
            return;
        }

        if (t instanceof IOException) {
            // 可重连的网络错误，执行重连操作
            Log.d(TAG, "Reconnecting due to network issue...");
            reconnect();
        } else {
            // 其他错误类型，不执行重连操作
            Log.d(TAG, "Error: " + t.getMessage());
        }
    }

    @Override
    public void onMessage(@NonNull WebSocket webSocket, @NonNull String text) {
        Log.d(TAG, "onMessage:");
        Log.d(TAG, "Received message: " + text);
    }

    @Override
    public void onClosing(@NonNull WebSocket webSocket, int code, @NonNull String reason) {
        Log.d(TAG, "onClosing: ");
        Log.d(TAG, "Connection is closing: " + reason);
    }

    @Override
    public void onClosed(@NonNull WebSocket webSocket, int code, @NonNull String reason) {
        Log.d(TAG, "onClosed: ");
        Log.d(TAG, "Connection closed: " + reason);
        executor.shutdown(); // 停止心跳任务
        // 在一段时间后重新建立连接
        // 重连间隔
        int reconnectInterval = 5000;
        // 重新建立连接
        executor.schedule(this::connect, reconnectInterval, TimeUnit.MILLISECONDS);
    }

    public void connect() {
        Request request = new Request.Builder()
                .url(url + userId)
                .build();
        webSocket = client.newWebSocket(request, this);
    }

    /**
     * 发送消息
     *
     * @param message 消息体
     */
    public void send(String message) {
        webSocket.send(message);
    }

    /**
     * 关闭连接
     */
    public void close() {
        webSocket.close(1000, "Goodbye, WebSocket!");
    }

    public void reconnect() {
        reconnectCount++;
        Log.d(TAG, "Reconnecting attempt #" + reconnectCount + "...");
        try {
            // 延迟一段时间后进行重连尝试
            Thread.sleep(RECONNECT_DELAY_MILLIS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        connect(); // 重新建立WebSocket连接  
    }
}
